package com.ym521.facecheck.core

import android.content.Context
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.util.Log
import com.ym521.facecheck.R
import com.ym521.facecheck.bean.ImageBitmap
import com.ym521.facecheck.callback.FaceCheckCallback
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.opencv.android.OpenCVLoader
import org.opencv.android.Utils
import org.opencv.core.Core
import org.opencv.core.Mat
import org.opencv.core.MatOfByte
import org.opencv.core.Size
import org.opencv.imgproc.Imgproc
import org.opencv.objdetect.FaceDetectorYN
import java.io.IOException
import java.io.InputStream

/**
 *@author Ym
 *E-mail: 2435970206@qq.com
 *createTime:2024/6/22
 *explain:
 *
 */
internal class _FaceCheck private constructor() : IFaceCheck {

    private lateinit var rgbaMat: Mat
    private lateinit var bgaMat: Mat

    companion object {
        private val TAG = "FaceCheck"

        //是否开启记忆功能 可动态配置
        var memoryEnabled = false

        //是否开启人脸检测可视化 可动态配置
        var visualizeEnabled = false

        fun build(): IFaceCheck {
            return _FaceCheck()
        }
    }

    private var imageAngleEngine: IImageAngleEngine? = null
    override fun initSDK(mContext: Context): IFaceCheck {
        imageAngleEngine = ImageAngleEngine
            .build()
        if (OpenCVLoader.initLocal()) {
            loadFaceModeRes(mContext.resources) {
                if (it == null) throw RuntimeException("Facecheck SDK 初始化失败")
                imageAngleEngine?.initMat(it)
            }
            rgbaMat = Mat()
            bgaMat = Mat()
        } else {
            throw RuntimeException("初始化 OpenCV 失败")
        }
        return this
    }

    private fun loadFaceModeRes(
        resources: Resources,
        callBack: (faceDetectorYN: FaceDetectorYN?) -> Unit
    ) {
        CoroutineScope(Dispatchers.Main).launch(Dispatchers.IO) {
            val buffer: ByteArray
            var ins: InputStream? = null
            try {
                ins = resources.openRawResource(R.raw.face_detection_yunet_2023mar)
                val size = ins.available()
                buffer = ByteArray(size)
                ins.read(buffer)
                val mModelBuffer = MatOfByte(*buffer)
                val mConfigBuffer = MatOfByte()
                val faceDetectorYN =
                    FaceDetectorYN.create(
                        OpenCVConst.ONNX,
                        mModelBuffer,
                        mConfigBuffer,
                        Size(480.0, 480.0)
                    )
                callBack(faceDetectorYN)
            } catch (e: IOException) {
                Log.e(TAG, "Failed to ONNX model from resources! Exception thrown: $e")
                callBack(null)
            } finally {
                ins?.close()
            }
        }
    }


    override fun setFaceCheckCallback(call: FaceCheckCallback) {
        imageAngleEngine?.setFaceCheckCallBack(call)
    }

    /**
     * 第一个方案
     * 只支持 RGBA 格式的Bitmap
     */
    override suspend fun faceCheckFromRgba(imgBitmap: ImageBitmap) {
        if (!imgBitmap.isUse() || imageAngleEngine == null) return
        val cropBitmap = convertToSquareBitmap(imgBitmap.bitmap)
        Utils.bitmapToMat(cropBitmap, rgbaMat)
        Imgproc.cvtColor(rgbaMat, bgaMat, Imgproc.COLOR_RGBA2BGR)
        imageAngleEngine?.let {
            if (!it.isFaceDetectorSizeSetting()) {
                it.setFaceDetectorSize(bgaMat.size())
            }
            it.imageAngleHandler(bgaMat)
        }
    }

    /**
     * Bitmap矩形转正方形
     */
    private var squareBitmap: Bitmap? = null
    private fun convertToSquareBitmap(srcBitmap: Bitmap): Bitmap? {
        // 获取原Bitmap的宽和高
        val width = srcBitmap.width
        val height = srcBitmap.height
        val length = Math.max(width,height)
        if (squareBitmap == null)
            squareBitmap =
                Bitmap.createBitmap(length, length, Bitmap.Config.ARGB_8888)
        return when {
            width > height -> {
                squareBitmap?.let {
                    val canvas = Canvas(it)
                    canvas.drawColor(Color.BLACK)
                    val left = 0f
                    val top = (width - height) * 1f
                    canvas.drawBitmap(srcBitmap, left, top, null)
                }
                return squareBitmap
            }
            width < height -> {
                squareBitmap?.let {
                    val canvas = Canvas(it)
                    canvas.drawColor(Color.BLACK)
                    val left = (height - width) * 1f
                    val top = 0f
                    canvas.drawBitmap(srcBitmap, left, top, null)
                }
                return squareBitmap
            }
            else -> {
                squareBitmap?.let {
                    val canvas = Canvas(it)
                    canvas.drawBitmap(srcBitmap, 0f, 0f, null)
                }
                return squareBitmap
            }
        }
    }

    /**
     * 第二个 方案
     * 通过旋转 bitMap 实现人脸检测
     */
    override suspend fun faceCheckFromRgba2(imgBitmap: ImageBitmap) {
        if (!imgBitmap.isUse() || imageAngleEngine == null) return

        imageAngleEngine?.let {
            if (!it.isFaceDetectorSizeSetting()) {
                val width = imgBitmap.bitmap.width
                val height = imgBitmap.bitmap.height
                val length = width.coerceAtLeast(height).toDouble()
                it.setFaceDetectorSize(Size(length, length))
            }
            it.imageAngleHandler2(imgBitmap.bitmap, rgbaMat, bgaMat)
        }
    }


    override fun release() {
        imageAngleEngine?.release()
        imageAngleEngine = null
        squareBitmap?.recycle()
        squareBitmap = null
        rgbaMat.release()
        bgaMat.release()
    }
}